package main

import (
	"fmt"
	"strings"
	"unicode"

	_ "github.com/go-sql-driver/mysql"
	"github.com/gohouse/gorose/v2"

	"io/ioutil"
	"github.com/spf13/viper"
)

var Engin *gorose.Engin

func DB() gorose.IOrm {
	return Engin.NewOrm()
}

//初始化数据库连接
func InitDB() *gorose.Engin {

	// 全局初始化数据库,并复用
	// 这里的engin需要全局保存,可以用全局变量,也可以用单例
	// 配置&gorose.Config{}是单一数据库配置
	// 如果配置读写分离集群,则使用&gorose.ConfigCluster{}
	engin, err := gorose.Open(&gorose.Config{Driver: viper.GetString("db.driver"), Dsn: viper.GetString("db.dsn")})
	if err != nil {
		fmt.Println(err)

	}
	Engin = engin
	return Engin
}

// 下划线写法转为驼峰写法
func Case2Camel(name string) string {
	name = strings.Replace(name, "_", " ", -1)
	name = strings.Title(name)
	return strings.Replace(name, " ", "", -1)
}

// 首字母小写
func Lcfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToLower(v)) + str[i+1:]
	}
	return ""
}

func main() {
	viper.SetConfigType("properties")
	viper.SetConfigFile("config/config.properties")
	err := viper.ReadInConfig() // 查找并读取配置文件
	if err != nil {             // 处理读取配置文件的错误
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}




	InitDB()

	dbclient := DB()

	filefolder :=viper.GetString("to.folder")
	//输出包名
	java_package := viper.GetString("java.package")

	schema := viper.GetString("db.schema")

	tables, _ := dbclient.Query("SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA =?", schema)

	for _, tab := range tables {
		//表名
		tablename := tab["TABLE_NAME"].(string)

		//代码初始化
		//包名
		code_package := fmt.Sprintf("package %s;", java_package)

		//import部分
		code_import := `import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
`

		//类名部分
		code_class_name_start := fmt.Sprintf(`@Accessors(chain = true)
@Data
@TableName(value = "%s")
public class %s implements Serializable {
`, tablename, Case2Camel(tablename))

		//字段列表
		cols, _ := dbclient.Query(`SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_TYPE, COLUMN_KEY, EXTRA, PRIVILEGES, COLUMN_COMMENT, GENERATION_EXPRESSION, SRS_ID FROM information_schema.COLUMNS
        where TABLE_SCHEMA=?
		and TABLE_NAME=?
		order by ORDINAL_POSITION
		`, schema, tablename)

		//字段部分
		code_fields := ""

		for _, col := range cols {

			//字段名
			COLUMN_NAME := strings.ToLower( col["COLUMN_NAME"].(string) )
			//是否主键
			COLUMN_KEY := col["COLUMN_KEY"].(string)
            //字段类型
			DATA_TYPE := col["DATA_TYPE"].(string)

            java_type :="String"

			if strings.Contains(DATA_TYPE,"int") {
				java_type ="Integer"
			}
			if strings.Contains(DATA_TYPE,"bigint") {
				java_type ="Long"
			}
			if strings.Contains(DATA_TYPE,"decimal") || strings.Contains(DATA_TYPE,"float") || strings.Contains(DATA_TYPE,"double") {
				java_type ="BigDecimal"
			}

			if strings.Contains(DATA_TYPE,"date") || strings.Contains(DATA_TYPE,"time"){
				java_type ="Date"
			}




			if COLUMN_KEY == "PRI" { //主键
				code_fields = code_fields + fmt.Sprintf(`@TableId(value = "%s")
private %s %s;
`,COLUMN_NAME,java_type,Lcfirst(Case2Camel(COLUMN_NAME)))
			} else {
				code_fields = code_fields + fmt.Sprintf(`@TableField(value = "%s")
private %s %s;
`,COLUMN_NAME,java_type,Lcfirst(Case2Camel(COLUMN_NAME)))
			
			}
		}


		code :=code_package +code_import+code_class_name_start +code_fields +"}"


        filepath :=filefolder +"/"+Case2Camel(tablename)+".java"
		code_bytes := make([]byte,0)
		code_bytes =append(code_bytes, 0xef )
		code_bytes =append(code_bytes, 0xbb  )
		code_bytes =append(code_bytes, 0xbf  )
		code_bytes =append(code_bytes, []byte(code)...)

		ioutil.WriteFile(filepath,[]byte(code),0644)
	}

}
